#include <string>
#include <cstring>

#include "HttpResponse.h"
#include "FastCGI.h"
#include "PhpHandler.h"
#include "ConfManager.h"

using namespace std;

PhpHandler::PhpHandler()
{
    _FastCGIObj = new FastCGI();
}

PhpHandler::~PhpHandler()
{
    delete _FastCGIObj;
}

void PhpHandler::ErrorResponse(int sockfd, const HttpRequest* req)
{
    HttpResponse response;
    response.SetHttpVersion(req->GetVersion());
    SetAndWriteBack(sockfd, response, "500", "Internal Server Error");

    close(sockfd);
}

void PhpHandler::Process(int sockfd, const HttpRequest* req)
{
    std::string fastCGIIP = ConfManager::Instance()->GetConfValueByKey("FASTCGI_IP");
    std::string fastCGIPort = ConfManager::Instance()->GetConfValueByKey("FASTCGI_PORT");

    if(fastCGIIP.empty() || fastCGIPort.empty())
    {
        ErrorResponse(sockfd, req);
        return;
    }

    int fastCGIfd = _FastCGIObj->ConnectFastCGI(fastCGIIP.c_str(), atoi(fastCGIPort.c_str()));

    if(fastCGIfd < 0)
    {
        ErrorResponse(sockfd, req);
        close(fastCGIfd);
        return;
    }

    _FastCGIObj->SetRequestID(sockfd);

    std::map<std::string, std::string> headerParams = req->GetHeadParams();

    // TODO: Should wrap these if-s into a function
    if (headerParams.find("Accept") != headerParams.end())
    {
        _FastCGIObj->AddParam("HTTP_ACCEPT", headerParams["Accept"].c_str());
    }

    if (headerParams.find("Accept-Encoding") != headerParams.end())
    {
        _FastCGIObj->AddParam("HTTP_ACCEPT_ENCODING", headerParams["Accept-Encoding"].c_str());
    }

    if (headerParams.find("Accept-Language") != headerParams.end())
    {
        _FastCGIObj->AddParam("HTTP_ACCEPT_LANGUAGE", headerParams["Accept-Language"].c_str());
    }

    if (headerParams.find("Cache-Control") != headerParams.end())
    {
        _FastCGIObj->AddParam("HTTP_CACHE_CONTROL", headerParams["Cache-Control"].c_str());
    }

    if (headerParams.find("Cookie") != headerParams.end())
    {
        _FastCGIObj->AddParam("HTTP_COOKIE", headerParams["Cookie"].c_str());
    }

    if (headerParams.find("Host") != headerParams.end())
    {
        _FastCGIObj->AddParam("HTTP_HOST", headerParams["Host"].c_str());
    }

    if (headerParams.find("Connection") != headerParams.end())
    {
        _FastCGIObj->AddParam("HTTP_CONNECTION", headerParams["Connection"].c_str());
    }
    else if (headerParams.find("Proxy-Connection") != headerParams.end())
    {
        _FastCGIObj->AddParam("HTTP_CONNECTION", headerParams["Proxy-Connection"].c_str());
    }

    if (headerParams.find("User-Agent") != headerParams.end())
    {
        _FastCGIObj->AddParam("HTTP_USER_AGENT", headerParams["User-Agent"].c_str());
    }

    if (headerParams.find("Referer") != headerParams.end())
    {
        _FastCGIObj->AddParam("HTTP_REFERER", headerParams["Referer"].c_str());
    }

    if (headerParams.find("Content-Type") != headerParams.end())
    {
        _FastCGIObj->AddParam("HTTP_CONTENT_TYPE", headerParams["Content-Type"].c_str());
        _FastCGIObj->AddParam("CONTENT_TYPE", headerParams["Content-Type"].c_str());
        _FastCGIObj->AddParam("HTTP_CONTENT_LENGTH", IntToStr(req->GetPostDataLen()).c_str());
        _FastCGIObj->AddParam("CONTENT_LENGTH", IntToStr(req->GetPostDataLen()).c_str());
    }

    if (headerParams.find("X-Requested-With") != headerParams.end())
    {
        _FastCGIObj->AddParam("HTTP_X_REQUESTED_WITH", headerParams["X-Requested-With"].c_str());
    }

    if (headerParams.find("Pragma") != headerParams.end())
    {
        _FastCGIObj->AddParam("HTTP_PRAGMA", headerParams["Pragma"].c_str());
    }

    std::string rootPath = ConfManager::Instance()->GetConfValueByKey("ROOT_PATH");
    _FastCGIObj->AddParam("DOCUMENT_ROOT", rootPath.c_str());

    std::string queryStr = req->GetGetStr();
    if(queryStr.empty())
    {
        _FastCGIObj->AddParam("QUERY_STRING", "");
    }
    else
    {
        _FastCGIObj->AddParam("QUERY_STRING", queryStr.c_str());
    }

    _FastCGIObj->AddParam("REMOTE_ADDR", req->GetClientIP().c_str());

    _FastCGIObj->AddParam("REMOTE_PORT", IntToStr(req->GetClientPort()).c_str());

    _FastCGIObj->AddParam("REQUEST_METHOD", HttpMethodToString(req->GetMethod()).c_str());

    _FastCGIObj->AddParam("REQUEST_URI", req->GetUrlAll().c_str());

    std::string scriptName = ConfManager::Instance()->GetConfValueByKey("DEFAULT_SCRIPT");
    if (!req->GetFileExt().empty())
    {
    	scriptName = req->GetUrl();
    }
    _FastCGIObj->AddParam("SCRIPT_FILENAME", (rootPath + scriptName).c_str());

    _FastCGIObj->AddParam("SCRIPT_NAME", scriptName.c_str());

    _FastCGIObj->AddParam("DOCUMENT_URI", scriptName.c_str());

    _FastCGIObj->AddParam("SERVER_ADDR", "will process later");

    if (headerParams.find("Host") != headerParams.end())
    {
        _FastCGIObj->AddParam("SERVER_NAME", headerParams["Host"].c_str());
    }

    _FastCGIObj->AddParam("SERVER_PORT", IntToStr(ConfManager::Instance()->GetPort()).c_str());

    _FastCGIObj->AddParam("SERVER_PROTOCOL", ConfManager::Instance()->GetServerProtocol().c_str());

    _FastCGIObj->AddParam("SERVER_SOFTWARE", ConfManager::Instance()->GetServerName().c_str());


    if(_FastCGIObj->Process(sockfd, req) < 0)
    {
        ErrorResponse(sockfd, req);
        close(fastCGIfd);
        return;
    }

    close(fastCGIfd);
    close(sockfd);
}
